<?php

namespace App\Http\Middleware\Api;

use App\Jobs\Api\SaveLastTokenJob;
use Closure;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Tymon\JWTAuth\Exceptions\TokenInvalidException;
use Tymon\JWTAuth\Http\Middleware\BaseMiddleware;

class RefreshTokenMiddleware extends BaseMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        //检测是否带有token,没有就抛异常
        $this->checkForToken($request);

        $present_guard = Auth::getDefaultDriver();

        $token = Auth::getToken();

        $payload = Auth::manager()->getJWTProvider()->decode($token->get());

        if (empty($payload['role']) || $payload['role'] != $present_guard){
            throw new TokenInvalidException();
        }

        try {
            //检测登录状态，正常则通过
            if ($this->auth->parseToken()->authenticate()){
                return $next($request);
            }
            throw new UnauthorizedHttpException('jwt-auth','未登录');
        }catch (TokenExpiredException $exception){
            //捕获到token过期抛出的异常。
            try {
                //刷新token
                $token = $this->auth->refresh();
                //使用一次性登录以保证此次请求成功
                Auth::onceUsingId(
                        $this->auth->manager()
                            ->getPayloadFactory()
                            ->buildClaimsCollection()
                            ->toPlainArray()['sub']
                    );
                $user = Auth::user();
                SaveLastTokenJob::dispatch($user,$token);
            }catch (JWTException $exception){
                //refresh也过期时，需要重新登录
                throw new UnauthorizedHttpException('jwt-auth',$exception->getMessage());
            }
        }

        return $this->setAuthenticationHeader($next($request),$token);
    }
}
